home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 20
/
Cream of the Crop 20 (Terry Blount) (1996).iso
/
os2
/
edm0406i.zip
/
EDMI4-6.INF
(
.txt
)
< prev
next >
Wrap
OS/2 Help File
|
1996-07-08
|
253KB
|
2,150 lines
ΓòÉΓòÉΓòÉ 1. Jul 1996 Title Page ΓòÉΓòÉΓòÉ
Portions copyright (c) by IQPac Inc.
Volume 4, issue 6
Microsoft Does it Again
It's like the ole' one-two body punch that you know is coming but can't do
anything about. Doesn't it sometimes seem like no one wants to do anything
about it, though? Peter Coffee reports in this week's PC Week that Microsoft
is not going directly to the object-oriented file system in Cairo but will
instead make constant incremental upgrades to NT to (eventually) achieve this
goal.
The really scary thing is that they'll get away with it again. Just like
they'll get away with the ActiveX confusion that they've created. According to
the opinions of the trade press, once the version of Visual Basic is released
that generates ActiveX controls, no one will remember how bad it really is. I
can relate - I had thought Basic was dead and buried until Microsoft
resurrected it and (worse yet) made it one of the most popular languages in the
"I'm not really a geek" market.
PC Expo is Here Again
All of this hoopla can only mean one thing (actually, it could mean several,
but that sounded good so I went with it) - PC Expo is back in town. I'm
beginning to wonder if I shouldn't apply for a hotdog vendor's license. Anyone
who has attended this show knows what I'm talking about - this is the only week
when hotdogs on the West Side cost $2.00 each, and that's the bargain price!
The show should be good, though. There is supposedly a separate section just
for the Internet and related technologies, which I am looking forward to
browsing. Also, who can forget all of the goodies, although the quality has
been declining in recent years (as I have been told. I haven't attended the
past two shows.)
Anyway, if you're planning on being there, send me email and we'll meet
somehow.
Cast Your Ballots!
Speaking of sending me email, I hope to soon have a working HTML form that you
can use to vote on your favorite article over the past months. If I don't have
it done soon, I will have to revert to email for the ballots. [sigh]
We have three prizes already generously donated by IBM which will go to the
winners. These aren't pledges - I have them here in my "toy room" (still
shrink-wrapped, I will proudly add). I will not yet divulge what they are,
however.
Our First Advertisement
EDM has its first victory! We are happy to welcome SPG to the (now-growing)
list of EDM sponsors.
My Absence
I've been absent the past week. I apologize, but I plead hard drive trouble as
the cause. It started last week with the corruption of the "EA DATA . SF"
file's FAT entry on my boot drive. This means, for those who haven't picked up
on it yet, that my desktop was lost totally. I didn't do anything to cause
this; it just happened sometime between the time I turned off the computer last
Sunday and the time I turned it on again the next evening.
The next night, the Boot Manager partition became the active one that was
booted - a feature I disabled a long time ago. The partition name was missing,
too.
That was enough for me. I booted to the command line, backed everything of
value up to the ZIP drive that I wrote about a few weeks ago, repartitioned,
reformatted, and reinstalled. (Un)fortunately, my version of Warp is the
original, pre-CONFIG.SYS/AUTOEXEC.BAT bug-fix, red box version that was
distributed to the press (who subsequently ate it for breakfast), and I didn't
want to reinstall that monster, so I conveniently used this as an excuse to
upgrade to Warp Connect. Oh, and I forgot to make a bootable DOS floppy (I
need my real-time MIDI recording capabilities), so I just had to buy DOS 7.0.
All-in-all, the day (Wednesday) wasn't so bad.
Voting is On!
Then, on Thursday, I discovered the bug that has been plaguing me since the
beginning of May; I fixed it and the result is that you are now able to vote
for your favorite articles. The winners get big prizes, so cast your vote
today!
Other changes on the site include the much-overlooked mistake that the Back
Issues and the Links pages were the same. Worse yet, I made this mistake
locally, so I didn't have a backup to fall upon. (I did have a sword, but
that's so messy.) We now have a growing list of links and are always looking
for more.
The Acknowledgments and Sponsors pages have been combined. This only makes
sense.
The Real World
But, enough of us. What's going on out there?
Another journalist has the solution to IBM's troubles - "What IBM really
needs to do is..." How many times have you heard this? I'll finish that
sentence by saying that IBM really needs to tell these people to shut up
("or something...huhuhuhuh"). Only when the ambient noise has been
eliminated can they concentrate on solving their problems.
IBM announces that it's buying Microsoft - just seeing if you're awake.
[grin]
Merlin gains another feature - Infoworld likened Merlin to the Swiss Army
knife, an analogy that is not ill-fitted at all. IBM announced plans to
include Notes Mail with the new version of OS/2, the first beta of which
will ship next week. This new version will not run any custom Notes
applications, however.
Quick! Everyone Do the Hokey Pokey!
Blah blah blah. I suppose it's that "time of the year" again. Some "high
priced consultant to IBM" said, according to Robert X. Cringely, that Merlin
better sell well or OS/2 is toast. I have a very nasty suspicion that I know
this person well, especially since he fits that description and is always
hooting about how OS/2 is doomed. He doesn't mind taking their money,
however.
Heh. Maybe he should become the "people's poet" by quitting his position so
that IBM can put an extra dollar or two into the OS/2 coffers.
"Well, gee, Wally. Redmond says everyone's moving to NT and this here high
priced consultant says that OS/2 is doomed, so I guess, yuck yuck, that we
should also do the 'hokey pokey.'"
That's us. Just call us "idiot's on a rope."
OS2Web is Back Up!
After the "Pe-Perlow Fi-asco" (that even has the proper rhythm), Jeff "Boomer"
Bakalchuck (I hope I spelled his name properly) has gotten everything in order
and the sight is once again at "full steam ahead." (Aye, aye, Captain.) If
you haven't visited in a while, the new look will pleasantly surprise you.
Stop by at http://www.teamos2.org/os2web.
From the IBM School of Marketing
It seems that Rogue Wave took that IBM route when it comes to marketing.
"Yessirree, yuck yuck, we'll build a better mousetrap and they'll come a
runnin'." I'll bet that you don't know that Rogue Wave has an OS/2 Java
development environment already on the market. Yeah, neither did we. We have
the name and number of someone at Rogue Wave that we hope to speak with
shortly about this. Look for a "First Looks" on this hopefully coming in an
issue soon.
PC Expo
I'm really surprised that no one asked me anything about PC Expo. I daresay
that if you weren't there, you didn't care; this would explain the lack of
interest. My beef at the show was to drum up support for EDM/2, including
selling advertising space, acquiring software for review, and generally making
myself known. Of course, I could've showed up in a katt outfit, but I didn't
want to be too conspicuous.
"So," you ask me, "what did you see?" Well, when I wasn't trying to hobnob
with the various product managers and such, I did manage to see...
Merlin
This was the hottest thing for OS/2 enthusiasts. Aside from the (amazing)
jugglers that were there, I hung around until late that afternoon for a more
intimate demo of the system. Since there was only one other person watching,
I got to ask questions about the system, what the components were like, etc.
It turns out that the task bar, a la Object Desktop, was "stolen" (almost a
direct quote from the IBM gentleman) from the Lotus Smartsuite. "I hope they
didn't pay the billions of dollars for that alone," queried the quantifying
Q-ster. (Heh, Katt doesn't know how easy he has things!)
The interface, however, was rather stunning and it will likely be the most
noticeable improvement over Warp. No, I haven't forgotten VoiceType, but I
don't yet believe that the majority of people are going to use it. Let's face
it - if everyone went for the new and better technology immediately, OS/2
would have smashed Windows into the ground a long time ago. No, people are
very inertial, especially when dealing with technology they don't quite yet
understand.
VoiceType
I don't want to detract from VoiceType, though. It worked fairly well,
although the demoers - is that a word? - did at times have trouble with it.
For the record, it was hard-to-tell if the problems were caused by the
software or the extreme amount of ambient noise in the large conference
center. I am looking forward to playing with it; hell, if it's good enough,
maybe I won't have to type in this column every week. I still have to get one
of those nifty headset microphones before I can use it. (It figures. I have
over $20,000 of musical equipment sitting next to my computer, but I don't
have a headset microphone.)
TeamConnection
This is a project management software package which runs on OS/2 using TCP/IP
as the network protocol for a truly client/server system allowing multiple
people to work on a large project simultaneously. IBM rattled off a whole
list of features to me, but I opted for the evaluation copy of the software.
Hopefully, we'll get the real McCoy and Brad will be able to review it in the
near future.
One thing we won't be able to test (I don't think so, at least) but is
something you should definately be interested in is distributed building of
your product. You have 30 computers connected via a network - why should only
one of them do all of the compiling? This feature definately sounds fun to
watch in action.
Visual Age
For those of you who are interested in cross-platform development, IBM's
Visual Age product was being demoed on OS/2 and NT with the same user
interface (for the most part). If you've complained about the performance of
the Visual Builder (who hasn't?), some help is on the way. According to the
gentlemen I spoke to, IBM segregated the code generator from the builder and
(if I remember correctly) rewrote the generator in C. The visual aspects of
the builder are still written in Smalltalk, I infered.
Where Was Everyone Else?
Besides IBM and Lotus, there was a small section of IBM's floor space
dedicated to ISV's. DevTech is the only ISV whose name I can remember,
though. This is getting scary, folks. Where was everyone else?
I was really disappointed to find (or not find, as the case may be) little
OS/2 software outside the confines of the IBM and Lotus sections. When I say
little, I mean little. There was so little software for OS/2 that I can't
even remember seeing any, but something inside tells me that I did indeed see
some OS/2 packages.
This is yet another testimony to the lack of support for OS/2 in the
marketplace. While I don't completely agree with the pronouncement of doom,
OS/2 is quickly headed for the ranks of the Amiga OS and Unix, i.e. well
known, but not popular among the mainstream users.
ΓòÉΓòÉΓòÉ 2. Copyright Notice ΓòÉΓòÉΓòÉ
Copyright Notice
EDM/2 is published by IQPac Inc. IQPac Inc. can be reached via U.S. Mail at
the following address:
IQPac Inc.
7 East Broadway, Box 804
New York, NY 10038
U.S.A.
Editor-in-chief Larry Salomon Jr. (larry_salomon@iqpac.com)
Associate editor Carsten Whimster (carsten_whimster@iqpac.com)
Contributing editor Brad Scharf (brad_scharf@iqpac.com)
Contributing editor Joe Wyatt (joe_wyatt@iqpac.com)
Contributing editor Gordon Zeglinski (gordon_zeglinski@iqpac.com)
CEO/President Larry Salomon Jr. (larry_salomon@iqpac.com)
All material is copyrighted by its original author. No part of this magazine
may be reproduced without permission from the original author.
This publication may be freely distributed in electronic form provided that
all parts are present in their original unmodified form. A reasonable fee may
be charged for the physical act of distribution; no fee may be charged for the
publication itself.
Neither IQPac Inc. nor this publication are affiliated with International
Business Machines Corporation.
OS/2 is a registered trademark of International Business Machines Corporation.
Other trademarks are property of their respective owners. Any mention of a
product in this publication does not constitute an endorsement or affiliation
unless specifically stated in the text.
The OS/2 Accredited Logo is a trademark of International Business Machines
Corporation and is used by IQPac Inc. under license. This On-line Publication
is independently produced by IQPac Inc. and IBM is not responsible in any way
for its contents.
IQPac Inc. is an accredited member of the IBM Independent Vendor League.
Copyright Notice - EDM/2 - Jul 1996 - Volume 4, Issue 6
ΓòÉΓòÉΓòÉ 3. How Do I Get EDM/2? ΓòÉΓòÉΓòÉ
How Do I Get EDM/2?
EDM/2 can be obtained in any of the following ways:
Anonymous FTP on the Internet
hobbes.nmsu.edu in the /os2/newsltr directory.
Elsewhere on the Internet
generalhq.pc.cc.cmu.edu in the /pub/newsletters/edm2 directory.
The EDM/2 mailing list. Send an empty message to edm2-info@knex.mind.org to
receive a file containing (among other things) instructions for subscribing to
EDM/2.
On Compuserve
All back issues are available in the forum OS2DF2, section 15.
On BBS's
From BBS's in Denmark, send email to Jesper Nielsen at jesniels@internet.dk for
a location near you.
How do I Get EDM/2? - EDM/2 - Jul 1996 - Volume 4, Issue 6
ΓòÉΓòÉΓòÉ 4. Watermarking Your Printouts ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 4.1. Watermarking Your Printouts ΓòÉΓòÉΓòÉ
Watermarking Your Printouts
Written by Larry Salomon, Jr.
Introduction
In the "how did they do that" category, watermarking is a concept that looks
easy but, for those with little graphics experience (like me), is more
difficult than apparent at first glance. For those who are not familiar with
the term "watermark," it is a textual element that has the following
properties:
It is drawn behind all other elements on a printed page.
It is unobtrusive so that it does detract from the reader's ability to
easily read what else is on the page
It is rotated at some arbitrary angle, usually spanning the page from the
lower left corner to the upper right corner
See figure 1 for an example of a watermark.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Figure 1) Sample watermark
Watermarking is usually performed to indicate a security level of a document
("Confidential") or to indicate that the printout comes from a demo or
unregistered version of an application. There are, however, many other
possible uses which you will discover.
This article will discuss how watermarking can be done in OS/2 and will
briefly cover topics such as color use, fonts, graphics boundary
determination, and rotational transformations.
Watermarking Your Printouts - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 4.2. How Would You Do It? ΓòÉΓòÉΓòÉ
How Would You Do It?
Before we begin coding, we should consider a high-level design so that we know
in what direction we are travelling; this will serve as our flowchart for the
function which will do the watermarking.
Our first decision will be to determine what the interface is. This allows us
to consider in advance the flexibility that we will offer the application
developer using this function and design with this flexibility in mind. Since
watermarking can be used in a variety of situations, the text to be used should
be specified by the caller. The angle of rotation should also be specified by
the caller to give more control over the look of the watermark. Finally, we
need the handle of the presentation space to be used. We have, therefore, the
following prototype:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
BOOL doWatermark(HPS hpsPrn,PCHAR pchText,USHORT usAngle);
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
As a corollary exercise to designing the prototype, let us consider any
limitations and/or restrictions that we will impose.
As we will see, rotations can only be done on a "normal" presentation
space, so the HPS must have been created with the GPIT_NORMAL flag in the
call to GpiCreatePS().
The presentation space must be associated with a printer device.
The printer driver and/or device must support color or dithering (i.e.
no monochrome printers)
If we were to rotate the text more than 90 degrees, it wouldn't be easily
readable, so the angle should be in the range 0-90 inclusive.
Now we may proceed to determining the procedure for drawing the watermark.
Consider the following problem: we want the text to be as large as possible
(without having it clipped on the printed page) but we cannot determine, at
compile time, the size of each character. How do we calculate this at run
time?
The solution is easy to describe: we set the size of the character box to
some value that we know to be too big and then draw the text; if the text is
too big, we reduce the size of the character box by some amount and repeat.
When the text completely fits within the printed page, we stop looping.
Sounds easy, huh? Since this is the only "difficult" part of the design, we
can now describe the procedure as such:
1. Indicate a rotation of the number of degrees specified.
2. Set the font to something "nice."
3. Set the character size to be very large.
4. Draw the text.
5. If the text is too big, reduce the character size by some amount and goto
step 4.
6. Set the text color to be very light.
7. Draw the text using the calculated character size.
8. Restore the font to the one originally in use.
This procedure will work, as we will see. For those of you sharp enough to
catch the caveat that drawing the text in the determination part will
obliterate the printout, keep reading.
Watermarking Your Printouts - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 4.3. Colors ΓòÉΓòÉΓòÉ
Colors
Although the Gpi subsystem added the concept of a color palette, I have never
investigated whether or not palettes will work with hardcopy devices. To save
myself the aggrevation, I decided to stick with logical color tables in RGB
mode, which amounts to the same thing. Logical color tables are a dated
concept that worked well when the majority of displays were EGA or VGA and
dithering had to be used to simulate the colors that we really wanted. Now that
SVGA is considered standard equipment, logical color tables are considered
obsolete. In other words, I probably doomed myself by using them. They work
for the moment, however, so I'll use them anyway.
A logical color table is a table of colors which is requested by the
application for use within a presentation space. Gpi maps these "logical"
colors to the "physical" colors defined by the hardware palette. For those
colors that cannot by described adequately, Gpi uses dithering (alternating two
or three colors in a 2x2 or 3x3 matrix) to simulate the color requested. These
are normally used when the default RGB values for the CLR_ constants are not
good enough and also when you want to specify the RGB value directly in the Gpi
calls. We need the latter capability, so let's tell the Gpi subsystem this:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
#define DW_TEXT_COLOR 0x00CCCCCC
else if (!GpiCreateLogColorTable(hpsPrn,0,LCOLF_RGB,0,0,NULL))
;
else if (!GpiSetColor(hpsPrn,DW_TEXT_COLOR))
;
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Figure 2) Switching to RGB mode.
GpiCreateLogColorTable() takes the following parameters:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
BOOL GpiCreateLogColorTable(HPS hpsHps,
ULONG ulFlags,
LONG lMode,
LONG lStart,
LONG lCount,
PLONG plTable);
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
hpsHps specifies the presentation space. ulFlags specifies zero or more LCOL_
flags and is unused by us. lMode specifies the mode of the color table and
affects how the remaining parameters are interpreted and may be one of the
following:
LCOLF_DEFAULT - returns the color table to the default mode, which is
indexed. This uses the CLR_ constants that we all know and love.
LCOLF_INDRGB - indicates that plTable should be interpreted as an array
of pairs of LONG values, where the first LONG is the index into the color
table where the second LONG (which is an RGB value) is to be placed.
LCOLF_CONSECRGB - indicates that plTable specifies an array of LONG
values (which is lCount large and contains RGB values) which replace the
corresponding entries in the color table beginning at lStart.
LCOLF_RGB - indicates that lStart, lCount, and plTable are to be ignored
and that RGB values will be used in any Gpi call that requires a color.
Note how we specify a very light gray for the color (0xCC is used for the red,
green, and blue components of the color). The results in almost transparent
text.
Watermarking Your Printouts - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 4.4. Fonts ΓòÉΓòÉΓòÉ
Fonts
In his book, Charles Petzold described a nice, generic way to enumerate the
fonts on a system and set the current font to be one of your own choosing.
While this is great for the general case and gleefully covers the situation
when a font is not installed on a system, it is my opinion that, if you need
one of the ATM fonts shipped with the system, this is too much work. Given the
awe that high-quality graphics generate and the ever-shrinking cost of disk
space, it is my claim that few people (if any) will choose not to install all
of the fonts that OS/2 includes. With this in mind, I now present the "poor
man's method of selecting an ATM font:" initialize a FATTRS structure with
zeros (except for three fields), call GpiCreateLogFont(), and then call
GpiSetCharSet().
Done. See how easy that was? Let's look at the details:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
faFont.usRecordLength=sizeof(faFont);
faFont.fsSelection=0;
faFont.lMatch=0;
strcpy(faFont.szFacename,"Helvetica");
faFont.idRegistry=0;
faFont.usCodePage=GpiQueryCp(hpsPrn);
faFont.lMaxBaselineExt=0;
faFont.lAveCharWidth=0;
faFont.fsType=0;
faFont.fsFontUse=FATTR_FONTUSE_OUTLINE | FATTR_FONTUSE_TRANSFORMABLE;
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Figure 3) Initializing the FATTRS structure.
As you can see, the only three fields that we initialize are the font name
(FATTRS.szFacename), the codepage (FATTRS.usCodePage), and the flags describing
what type of font we want (FATTRS.usFontUse). As you can also see above,
initializing these fields is trivial. The flags FONTUSE_TRANSFORMABLE and
FONTUSE_OUTLINE indicate that we want a font that is "transformable" (i.e.
rotatable and resizable) and is an ATM font, respectively.
Shown below is the code to actually acquire the font for use.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
#define DW_FONT_HELV 1
//----------------------------------------------------------------------
// Create the logical font.
//----------------------------------------------------------------------
else if (GpiCreateLogFont(hpsPrn,NULL,DW_FONT_HELV,&faFont)==GPI_ERROR)
;
//----------------------------------------------------------------------
// Set the font into the HPS.
//----------------------------------------------------------------------
else if (!GpiSetCharSet(hpsPrn,DW_FONT_HELV))
;
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Figure 4) Creating the logical font and setting it is the current font.
GpiCreateLogFont() creates an association between the HPS and the physical
font. It takes the following parameters:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
LONG GpiCreateLogFont(HPS hpsHps,
PSTR8 psName,
LONG lFontId,
PFATTRS pfaAttrs);
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
hpsHps specifies the presentation space in which a logical font which
represents the physical font will be created. psName is used for creating
SAA-conforming metafiles and is not used normally (specify NULL for this).
lFontId is the identifier by which the font will be known and must be unique
for this HPS. pfaAttrs points to the FATTRS structure which describes the font
we want. It returns FONT_MATCH if the font was found, FONT_DEFAULT if the font
was not found but a substitute font was, or GPI_ERROR if an error occurred.
GpiSetCharSet() specifies the current font to be used and takes the following
parameters.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
BOOL GpiSetCharSet(HPS hpsHps,LONG lFontId);
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
hpsHps specifies the presentation space. lFontId is the identifier of the font
used in the GpiCreateLogFont() call.
Now that we have the font we want, we have to know how to specify the size that
we want. This only pertains to transformable fonts, which is why we specified
FONTUSE_TRANSFORMABLE in the FATTRS structure.
Fixed Decimal Arithmetic
When the Gpi subsystem was developed, floating point processors were not part
of the CPU, nor were they present as separate chips in the majority of
computers used at that time. So, to avoid the penalty of emulating floating
point operations in software, the Gpi developers decided to use fixed point
arithmetic when non-integral numbers were needed. For those of you unfamiliar
with the concept, fixed point arithmetic implies a decimal point, even though
one is not actually specified in the number.
The Gpi subsystem adds a twist to this, however. Instead of using base-10, it
uses base-10 only for the integer part of the number and base-64K for the
fractional part. In other words, if you have fixed point number i.f, you
convert this to a floating point number using the formula i+f/64K. This
denominator was not chosen to be sadistic. You will remember that 64K-1 is the
maximum value expressable in 16- bits, which allows us to imply the denominator
and yet get a complete range of fractional values. If you restrict the integer
portion to 16-bits also, the total number fits nicely in a ULONG.
Why is all of this relevant? Because character sizes are specified using
fixed-point numbers, of course. Let me now introduce the SIZEF structure which
is similar to the SIZEL structure except that the cx and cy fields are of type
FIXED instead of LONG. Yes, yes, they amount to the same thing, but it's the
principle that matters. The only other piece of information that you need to
know is that fonts are designed such that they display with no distortion if
and only if the horizontal component of the character size is equal to the
vertical component. (The box that has the dimensions of the character size is
known as the "character box.")
The code to set the character box (initially) is shown below. Note the
(necessary) call to GpiSetCharMode() which tells Gpi that we want to rotate
text in the presentation space.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
//----------------------------------------------------------------------
// Get the HPS dimensions. GpiQueryPS() does not have an error return
// code defined.
//----------------------------------------------------------------------
GpiQueryPS(hpsPrn,&szlHps);
szfChar.cx=MAKEFIXED(szlHps.cy/2,0);
szfChar.cy=szfChar.cx;
:
:
//----------------------------------------------------------------------
// Set the character mode to 3 so that we can rotate them.
//----------------------------------------------------------------------
else if (!GpiSetCharMode(hpsPrn,CM_MODE3))
;
else if (!GpiSetCharBox(hpsPrn,&szfChar))
;
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Figure 5) Setting the character box to its initial value.
Again, see how easy this is? And you thought fonts were difficult!
Watermarking Your Printouts - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 4.5. Transformations ΓòÉΓòÉΓòÉ
Transformations
One class that I had to take as a Computer Science major which was both
interesting and boring at the same time was Linear Algebra. In this class we
learned everything about matrices we ever wanted to know and even some stuff
that we never wanted to know. (How many of you actually used your knowledge of
Eigen vectors after graduating?) One interesting application of matrices is
transformations. In a nutshell, by properly initializing a matrix of the
appropriate size, one can scale, rotate, shear, or even map a point in 3-D
space to 2-D space.
The Gpi subsystem provides two ways of doing transformations, just as it does
fonts: the hard way and the easy way. Because we'll never finish this article
if we describe the hard way, we'll use the easy way. As with fonts, the easy
way doesn't provide the same flexibility as the hard way, but we don't need to
perform all sorts of fancy transformations either. Just a simple rotation
would be sufficient.
Fortunately, the easy way also includes a function to do this for us:
GpiRotate(). It applies a rotation of an arbitrary angle to an entity called
(as you would imagine) a transformation matrix.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
BOOL GpiRotate(HPS hpsHps,
PMATRIXLF pmlMatrix,
LONG lFlags,
FIXED fAngle,
PPOINTL pptlOrigin);
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
hpsHps specifies the presentation space. pmlMatrix points to the
transformation matrix, which we will not describe here. lFlags specifies how
the rotation is to be performed. fAngle specifies the angle of rotation in
degrees. pptlOrigin specifies the point around which the rotation is to be
performed.
lFlags can be one of the following values:
TRANSFORM_REPLACE - specifies that the result is to replace the
transformation already specifed in pmlMatrix.
TRANSFORM_ADD - specifies that the rotation is to be applied after the
transformation specified in pmlMatrix.
TRANSFORM_PREEMPT - specifies that the rotation is to be applied before
the transformation specified in pmlMatrix.
The resulting transformation matrix is returned in pmlMatrix regardless of the
option specified.
What does this do for us? When the resulting transformation matrix is applied
to the HPS, it allows us to draw using a coordinate system oriented in the
usual fashion (i.e. the x axis is horizontal and increases to the right and
the y axis is vertical and increases upward). The output, however, is rotated
by the angle specified.
The Gpi subsystem provides many layers of transformation, and we will not
describe them here because they are too advanced for the scope of this article
(read: I don't understand them myself). Suffice it to say that the function
we need to effect the transformation represented by pmlMatrix is
GpiSetModelTransformMatrix(). It takes the following parameters:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
BOOL GpiSetModelTransformMatrix(HPS hpsHps,
LONG lInitFields,
PMATRIXLF pmlMatrix,
LONG lFlags);
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
hpsHps specifies the presentation space. lInitFields is the number of fields
in pmlMatrix that are initialized and, for us, will always be 9 (meaning that
a transformation matrix has size 3x3). pmlMatrix specifies the transform to
be applied. lFlags specifies how the transformation is to be applied and can
have the same value as the equivalent parameter in GpiRotate().
The code to set the rotation is shown below:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
//----------------------------------------------------------------------
// Rotate about the center of the page.
//----------------------------------------------------------------------
else if (!GpiRotate(hpsPrn,
&mxRotate,
TRANSFORM_REPLACE,
MAKEFIXED(usAngle,0),
&ptlPoint))
;
else if (!GpiSetModelTransformMatrix(hpsPrn,
9,
&mxRotate,
TRANSFORM_REPLACE))
;
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Figure 6) Setting up the rotation.
Watermarking Your Printouts - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 4.6. Graphics Boundaries ΓòÉΓòÉΓòÉ
Graphics Boundaries
The title of this section implies that it is possible to determine the
boundaries of any given set of graphics commands. Since it would be useless
otherwise, it makes sense to assume that it is also possible to do so without
affecting the current output in the HPS.
There is a little known, but powerful, Gpi function which performs both of
these actions: GpiSetDrawControl(). It, in a general sense, controls whether
or not specific functionality in the Gpi is in effect. (Yes, this is
confusing. Keep reading and it should make sense.) It takes the following
parameters:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
BOOL GpiSetDrawControl(HPS hpsHps,LONG lControl,LONG lValue);
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
hpsHps specifies the presentation space. lControl specifies a DCTL_ constant
indicating which attribute of the Gpi subsystem you which to change. lValue
specifies DCTL_ON or DCTL_OFF to turn the attribute on or off, respectively.
The two values of lControl that we're interested in are DCTL_DISPLAY and
DCTL_BOUNDARY:
DCTL_DISPLAY specifies whether or not anything is to be drawn on the output
device. With the exception of GpiErase() any drawing function results in a NOP
if DCTL_OFF is specified.
DCTL_BOUNDARY specifies if the Gpi subsystem should keep track of the extents
of the units (pels, low English, etc.) that were affected by a drawing
command. This information can be retrieved using GpiQueryBoundaryData(). It
is not affected by the state of the DCTL_DISPLAY attribute.
You should already be able to see how we are going to use this function.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
//----------------------------------------------------------------------
// Turn off drawing and turn on boundary collection
//----------------------------------------------------------------------
else if (!GpiSetDrawControl(hpsPrn,DCTL_DISPLAY,DCTL_OFF))
;
else if (!GpiSetDrawControl(hpsPrn,DCTL_BOUNDARY,DCTL_ON))
;
:
:
//-------------------------------------------------------------------
// Turn on drawing and turn off boundary collection
//-------------------------------------------------------------------
else if (!GpiSetDrawControl(hpsPrn,DCTL_DISPLAY,DCTL_ON))
;
else if (!GpiSetDrawControl(hpsPrn,DCTL_BOUNDARY,DCTL_OFF))
;
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Figure 7) Setting the drawing and boundary data collection attributes.
The code above allows us to, inside the bracket, determine the character box
size for the watermark.
This stuff is so easy, you should be writing this article instead of me.
Watermarking Your Printouts - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 4.7. The Result ΓòÉΓòÉΓòÉ
The Result
We now have enough knowledge to successfully implement the design that we
deduced earlier. The function as well as the application which calls the
function are in the sample source code that accompanies this article. Although
you should be able to understand the code competely, any questions or comments
are welcome via email; my address is larry_salomon@iqpac.com . Enjoy!
Watermarking Your Printouts - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 5. A Progress-indicating Status Line in C++ (Part 2) ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 5.1. A Progress-indicating Status Line in C++ (Part 2) ΓòÉΓòÉΓòÉ
A Progress-indicating Status Line in C++ (Part 2)
Written by Stefan Ruck
Introduction
In the first part of this small series, published in EDM/2 Volume 4, Issue 5, I
introduced the progress-indicating status line and the needed message handler
to you. This time I will show you a simple base file class which is wrapped
around the API-calls and a derived class which sends status messages to a given
status line.
A Progress-indicating Status Line in C++ (Part 2) - EDM/2 - Jul 1996 - Volume 4
Issue 6
ΓòÉΓòÉΓòÉ 5.2. The Base File Class ΓòÉΓòÉΓòÉ
The Base File Class
The primary purpose of this class named AFile is to hide the main file-handling
API functions. It just covers opening, reading, writing and of course closing
a file. Let's have a look at its member.
The class AFile is defined in afile.hpp and afile.cpp
The Constructor Member
There is only one constructor which takes two arguments, pBuffer (a PVOID) and
ulBufferSize (a ULONG). They are initialized to zero by default.
What are these arguments good for? If you know the buffer you want to read the
file's contents into, and it's size, you can pass a pointer to the buffer and
the buffer's size to the file object as soon as you create it. When you do any
operation (reading, writing) later on this file you don't have to pass the
buffer and its size anymore because they are already known. This may be
useful, e.g. for configuration files.
The members which store this information are declared as const so they can't be
changed after construction.
The open Members
The difference between the two AFile::open members is the way you pass the
filename. It can be a pointer to a string or a reference to an IString object.
The other arguments are similar to the DosOpen function. The only difference
is that the file handle is not needed because it's a private member of the file
object.
The AFile::reOpen member can only be used when a file object was opened before
and is actually closed. Because the filename of a AFile object is kept in a
private member you don't have to pass it again when you re-open the same file
using the same object.
The Close Member
This member is implemented for closing the file during the lifetime of the file
object. Destroying a file object always closes the file.
The read and write Members
The default value of both parameters (PVOID pBuffer and ULONG ulBufferSize) is
0L. If you call AFile::read or AFile::write without passing a pointer to the
buffer and/or the buffer's size the values passed to the constructor are given
to the DOS-API-functions.
In addition to the OS/2 API return-values there are three more return-values:
AFILE_FILE_NOT_OPEN is returned in case the file connected to the object
is not open.
AFILE_NO_BUFFER_POINTER indicates that no pointer to a buffer is passed
to the constructor or to the member. And AFILE_NO_BUFFER_SIZE means that
the size of the buffer is missing.
The Refresh-Flag on AFile::getFileSize
This flag is used internally when the AFile::queryFileInfo member is called.
If it is set to true DosQueryFileInfo is called even if nothing about the file
has changed. If it is set to false DosQueryFileInfo is only called when it
was not called before (AFile::m_pFilestatus3, which keeps the file info, is
not set in this case). You have to handle it yourself when the refresh-flag
should be set.
A Progress-indicating Status Line in C++ (Part 2) - EDM/2 - Jul 1996 - Volume
4 Issue 6
ΓòÉΓòÉΓòÉ 5.3. The Message-Sending File Class ΓòÉΓòÉΓòÉ
The Message-Sending File Class
The main purpose of this article is to present a class which uses the
progress-indicating status line to show the state of a process. This class is
AEditFile. It is defined in editfile.hpp and editfile.cpp.
We can't use AFile directly because the methods AFile::read and AFile::write do
not return until they have finished and the whole file is read / written. So
what we need now are methods which read/write the data not in one big step but
in a few small ones. They are AFileEdit::read and AFileEdit::write.
The class AFile is the base class of AEditFile, which posts MYM_STATUS_PROCEED
messages (I hope you remember this message) to the status line while
reading/writing a file. The differences between this class and AFile are the
members for reading/writing, and the fact that this class keeps the file's
contents itself. So you can't pass a pointer to the buffer or the buffer's
size to the constructor.
The size of the file can't be changed.
This class doesn't work on files of no size.
I think there is no explanation needed for the constructor and destructor.
The read Member
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
//**************************************************************************
// AEditFile :: read - read the data into the buffer *
//**************************************************************************
APIRET AEditFile :: read (HWND hwndStatusLine)
{
ULONG ulBytesLeftToRead = m_ulFileSize; // set the variables
ULONG ulReadAtBufferPos = 0;
APIRET ret;
if(!m_pFileContents) // no buffer allocated?
throw m_pFileContents; // throw an exception
m_bStopProcess = false; // do not stop the process
while(ulBytesLeftToRead) // as long as there are still some bytes left to read
{
ret = AFile :: read (m_pFileContents + ulReadAtBufferPos, // read a block of data
(ulBytesLeftToRead > (ULONG) eBytesToRead ? eBytesToRead : ulBytesLeftToRead));
if(ret && ret != ERROR_MORE_DATA) // a serious error occured?
break; // yes, break the loop
if(m_bStopProcess) // stop the process?
{ // yes
m_bStopProcess = false; // reset the flag
return (ERROR_MORE_DATA); // return
}
if(hwndStatusLine) // is a handle of a status line passed?
WinPostMsg (hwndStatusLine, MYM_STATUS_PROCEED, 0, 0); // yes, post the message
ulBytesLeftToRead -= getBytesRead (); // decrease the number of bytes left to read
ulReadAtBufferPos += getBytesRead (); // increase the position where to place the data
}
return (ret);
}
Figure 1) AEditFile::read
AEditFile holds its own buffer (see "The allocateDataBuffer Member" later in
this article). So there's no pointer to a buffer or the buffer size needed as
a parameter. But this member needs the HWND of the status line which indicates
the progress.
Because we read the data in (maybe) several steps, we must compute the number
of bytes left to read (stored in ulBytesLeftToRead). And we have to keep the
position to append the new data block in the buffer. This value is kept by
ulReadAtBufferPos.
If the buffer was not allocated by AEditFile::allocateDataBuffer, an exception
of type char * is thrown.
As you might remember we want to use this member to read a file inside of a
multi-threaded environment. Setting the m_bStopProcess to true using
AEditFile::stopProcess, the main thread is able to terminate the operation
without terminating the sub thread e.g. by calling IThread::stop (which should
only be used in cases of "abnormal termination". For further information refer
to Leong, Law, Love, Tsuji, Olson, "OS/2 C++ Class Library, Power GUI
Programming with C Set++", New York, 1993, John Wiley & Sons, p. 533f).
AEditFile::stopProcess is useful e.g. if the user closes the program or wants
to abort the process by pressing ESC. If the process is stopped by setting
AEditFile::m_bStopProcess to true, AEditFile::read returns ERROR_MORE_DATA.
AEditFile::read uses AFile::read to read the data. But it calls AFile::read
several times, depending on the file's size. Every time AFile::read is called,
a block of AEditFile::bytesToRead or ulBytesLeftToRead bytes, depending on the
amount of bytes left to read, is read. As soon as a file is larger than
AEditFile::bytesToRead, it will be read in several steps. Every time a block is
read, a MYM_STATUS_PROCEED message is posted to the status line.
This line of code may seem a little bit cryptic to some of you: ret = AFile ::
read (m_pFileContents + ulReadAt BufferPos, (ulBytesLeftToRead > (ULONG)
eBytesToRead ? eBytesToRead : ulBytesLeftToRead));. Well, I use the ?
operator to check if the block of data left to read (ulBytesLeftToRead) is
larger than the block I want to read by default (AEditFile::eBytesToRead). If
so, AEditFile::eBytesToRead bytes is passed to AFile::read, oth erwise
ulBytesLeftToRead is passed.
Because we may not read the whole file in at once, AFile::read may return
ERROR_MORE_DATA. This is correct, so I accept this return value. Any other
non-zero return-value will break the read loop.
Only if a handle to a status line window is passed will the MYM_STATUS_PROCEED
message be posted.
Every time a block of data is read, the position to place the data inside of
the buffer (ulReadAtBufferPos) is increased by bytes read (returned by
AFile::getBytesRead) while the ulBytesLeftToRead is decreased by the same
value.
The write Member
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
//**************************************************************************
// AEditFile :: write - write the data from the buffer *
//**************************************************************************
APIRET AEditFile :: write (HWND hwndStatusLine)
{
ULONG ulBytesLeftToWrite = m_ulFileSize; // set the variables
ULONG ulWriteFromBufferPos = 0;
APIRET ret;
if(!m_pFileContents) // no buffer allocated?
throw m_pFileContents; // throw an exception
m_bStopProcess = false; // do not stop the process
while(ulBytesLeftToWrite) // as long as there are still some bytes left to write
{
if((ret = AFile :: write (m_pFileContents + ulWriteFromBufferPos, // write a block of data
(ulBytesLeftToWrite > (ULONG) eBytesToRead ? eBytesToRead : ulBytesLeftToWrite))))
break; // if not 0 == NO_ERROR returned, break the loop
if(m_bStopProcess) // stop the process?
{ // yes
m_bStopProcess = false; // reset the flag
return (ERROR_MORE_DATA); // return
}
if(hwndStatusLine && ulBytesLeftToWrite) // is a handle of a status line passed?
WinPostMsg (hwndStatusLine, MYM_STATUS_PROCEED, 0, 0); // yes, post the message
ulBytesLeftToWrite -= getBytesWritten (); // decrease the number of bytes left to write
ulWriteFromBufferPos += getBytesWritten (); // increase the (buffer-)position from where to write the data
}
return (ret);
}
Figure 2) AEditFile::write
This member is similar to AEditFile::read, so I think there is just a little
bit of explanation needed.
The proceed message is only posted if there are bytes left to write. Otherwise
the status line will display a per centage greater than 100.
AEditFile::write writes the data, like DosWrite does, at the current position
of the file pointer set by former read or write operations. To set the
file-pointer, you have to use DosSetFilePtr or better create a
AFile::setFilePtr member and use this one. I did not include such a member to
AFile because I never keep a file open while editing it. And on every file
open the file-pointer is set to the beginning of the file.
The allocateDataBuffer Member
This member is used to allocate the memory which keeps the file's contents. You
should not call it before the file itself is open because the file size is
needed.
If the memory is allocated successfully or a block of memory is already
allocated, it returns true. If the file is not open, it returns false. It
throws an exception of type ULONG if the size of the file is 0 or the size can
not be retrieved. An exception of type char * is thrown if the memory
allocation itself fails. So this member should be used always inside a
try/catch block.
A Progress-indicating Status Line in C++ (Part 2) - EDM/2 - Jul 1996 - Volume 4
Issue 6
ΓòÉΓòÉΓòÉ 5.4. Concluding Remarks ΓòÉΓòÉΓòÉ
Concluding Remarks
Neither of the classes nor AStatusLine have a copy constructor. Because some
data members are just pointers to a memory block allocated during runtime, you
must not copy objects of these classes. The reason is that the default copy
constructor can't handle those members in the correct way.
In AFile, there are some members set but never used. I included them for
future methods, e.g like getOpenFlags, getOpenMode.
You might miss the two messages left defined in Part I, MYM_PROCESS_START and
MYM_PROCESS_END.
In principle they can be posted by AEditFile::read and AEditFile::write, but I
think they should be posted by the main object which starts the process because
one of the values passed by the MYM_PROCESS_START message is a resource id. If
you want to use the AEditFile class in several projects and use AEditFile::read
and AEditFile::write for posting the start message, you must take care that
there is always a resource defined which matches the resource id passed in this
members.
The main object, which uses the classes shown in part I and part II in a
(really) simple multi-threaded environment, will be the contents of the last
part.
A Progress-indicating Status Line in C++ (Part 2) - EDM/2 - Jul 1996 - Volume 4
Issue 6
ΓòÉΓòÉΓòÉ 6. The Codesmith's Library ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 6.1. The Codesmith's Library ΓòÉΓòÉΓòÉ
The Codesmith's Library
Written by Joe Wyatt
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
In The Codesmith's Library, I focus on development books and materials. I
write this column from the point of view of an intermediate PM C programmer and
intermediate REXX programmer. Pick up whichever book strikes your fancy, and
join the growing group of people following our PM programming columns. I have
already reviewed a number of beginner books, and will try to concentrate more
on intermediate techniques and special topics from now on.
Please send me your comments and thoughts so that I can make this column what
you want it to be. I read and respond to all mail.
Message Functions, OS/2 Quick Reference Library Volume 2 is possibly the only
book on the market which covers all the OS/2 messages. It is volume 2 of a 6
volume series.
The Codesmith's Library - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 6.2. Errata ΓòÉΓòÉΓòÉ
Errata
Yet again I am going to trumpet The OS/2 API Project. It is getting quite
useful, with more than 36 APIs on site, as well as over 75 #define's. Have a
look, and if you have the time, chip in by writing up one or more APIs and
sending them to me. I will also happily listen to any and all suggestions
regarding layout and format. The more people help out, the quicker this
project will become very helpful. The INF version is now out, although it is a
touch behind the HTML version. Check it out at [Editor's note: EDM/2 has
"absorbed" the OS/2 API Project, although it continues to be a separate entity.
It's location has changed, however, and it is reflected in the URL below.]:
http://www.iqpac.com/edm2/os2api/index.html
The OS/2 API Project aims at documenting the entire OS/2 API and distributing
it as a free document, to help out people who can't afford the IBM
documentation, or have something better to spend their money on. I figure it
can only help the number of OS/2 programs out there if more people have access
to this information.
The Codesmith's Library - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 6.3. OS/2 Quick Reference Library, Volume 2, Message Functions ΓòÉΓòÉΓòÉ
OS/2 Quick Reference Library, Volume 2, Message Functions
This is the second book in the same series as WIN Functions, OS/2 Quick
Reference Library Volume 1, which I previously reviewed. Here are the chapter
headings:
1. How to Use This Book
2. Notebook Control Messages
3. Button Control Messages
4. Combo Box Messages
5. Container Control Messages
6. Direct Manipulation Messages
7. Entry Field Messages
8. File Dialog Messages
9. Font Dialog Messages
10. Help Manager Messages
11. List Box Control Messages
12. Multiline Entry Messages
13. Menu Control Messages
14. Profile Messages
15. Scroll Bar Messages
16. Slider Control Messages
17. Static Control Messages
18. Spin Button Messages
19. Title Bar Messages
20. Value Set Control Messages
21. Window Messages
Appendix A: Data Type Structures
Appendix B: Error Code Definitions
Appendix C: Container Notification Codes
As you can see from the picture of this book, it is bound with ring binding.
All reference books should be bound this way, or at least with the
O'Reilly-style binding, but unfortunately this is rarely the case. `Nuff
said.
At the start of each chapter, there is a little section with cross-references
to other related messages. Unfortunately, there are no page numbers given,
only which chapter they are in.
Each message has a title, a brief description, message declarations (ie.
param1, param2, and reply), parameters, returns, remarks and default
processing. The remarks section is where you will probably spend most of your
reading time, but unfortunately, I find that it is not always complete. Many,
if not most, of these messages are sent by a call to some API, but this
reference does not discuss these related APIs. In addition, some special
properties of certain messages are not discussed either, such as the fact that
sending MM_SETDEFAULTITEMID actually converts a cascade menu to a conditional
cascade menu. Even though this is a message reference, I find myself wishing
for a stronger connection to the related APIs. In general, however, the
descriptions are quite good, if occasionally incomplete.
The layout of the chapters is logical, being alphabetical by message name
though the whole book. The lack of cross-reference page-numbers is a bother,
though. As an example, if you are looking for the LM_SEARCHSTRING message,
you will find it on page 186. At the start of the chapter, page 175, there
are references to other related messages, such as WM_CONTROL. To find this,
you must then flip around until you find it on page 372. The fact that the
messages are alphabetical through the whole book helps somewhat, but this is
still 3 separate searches though the pages. This could have been minimized by
following the same format as the OS/2 Warp API series, with page numbers
listed, or even the same as the earlier book in the same series!
Again, this book is not a tutorial by any means, but it does provide a
description for every message I have ever come across, which is more than any
other book on the market can say.
I recommend this book, but despite the fact that it is competent, it misses
the opportunity to go that extra mile and become the great reference book that
some of its companion books are. I suspect that it will be surpassed by the
next message book on the market, unless it is updated first.
The Codesmith's Library - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 6.4. Summary ΓòÉΓòÉΓòÉ
Summary
This little reference book has the only message descriptions out there
currently, and it is quite invaluable as such. Nonetheless, there are a number
of convenience features missing, such as page number references, see also
sections, coloured chapters (on the page ends, a la Sidekick, see volume 4
issue 2), and descriptions of related functions. It is good, but due to the
lack of these items, I feel that a newer book could quickly eclipse this one. I
rate it a B.
The Codesmith's Library - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 6.5. Book Reviewed ΓòÉΓòÉΓòÉ
Book Reviewed
Message Functions, OS/2 Quick Reference Library Volume 2, Scholin
- Van Nostrand Reinhold, ISBN 0-442-01898-3, $20US, $30CAN.
Note that Van Nostrand Reinhold has sold its OS/2 library to John
Wiley and Sons, and hence this book will now be obtainable
through John Wiley, rather than VNR.
- Intended audience: PM C Programmers
- Mark: B
A good reference, but misses out on several convenience features. This
is the only message reference on the market currently, to my knowledge,
so it wins by default.
NOTES
Please note that books aimed at different audiences should only be compared
with great care, if at all. I intend to concentrate on the strong points of
the books I review, but I will point out any weaknesses in a constructive
manner.
LEGEND
BOOK: The name of the book, and the author(s)
PUBLISHING INFORMATION: Publishing company, ISBN, and approximate price.
AUDIENCE: This is a description of the audience I think the book targets
best. This is not intended as gospel, just a guideline for people not
familiar with the book.
MARK: My opinion of the success of the book's presentation, and how well it
targets its audience. Technical content, accuracy, organization, readability,
and quality of index all weigh heavily here, but the single most important
item is how well the book covers what it says it covers. Many books try to
cover too much, and get a lower mark as a result.
+------+-------------------------------------------------------------------------+
| MARK | DESCRIPTION |
+------+-------------------------------------------------------------------------+
| A+ | Ground-breaking, all-around outstanding book |
| A | Excellent book. This is what I want to see happen a lot |
| A- | Excellent book with minor flaws |
| B+ | Very good book with minor flaws or omissions |
| B | Good book with some flaws and omissions |
| B- | Good book, but in need of improvement |
| C+ | Mediocre book with some potential, but in need of some updating |
| C | Mediocre book with some good sections, but badly in need of fixing |
| C- | Mediocre book, little good material, desperately in need of an overhaul |
| D | Don't buy this book unless you need it, and nothing else exists |
| F | Don't buy this book. Period |
+------+-------------------------------------------------------------------------+
COMMENTS: This is a very brief summary of the review proper.
The Codesmith's Library - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 6.6. Coming Up ΓòÉΓòÉΓòÉ
Coming Up
I do not yet have a book for next month. I have been promised several of the
books below, however.
Other books I would like to review:
The Art of OS/2 Warp Programming, Panov, Salomon, Panov - I have recently
noticed that this has been out for a while. Hint, hint, Larry. [Lest anyone
think I am stingy, I finally got in touch with my editor - after much confusion
and miscommunication - and a copy is on the way. - Larry]
Objects for OS/2, Tate - This sounds interesting, but is it C or C++? Time will
tell.
The Design of OS/2, 2nd Edition, Kogan and Deitel - I am having trouble getting
a copy of this, so if anyone can help, please do. A 1st edition would do me
fine too.
OS/2 C++ Class Library: Power GUI Programming with CSet++, Law, Leong, Love
and Tsuji - This is on the way I am told.
OS/2 Presentation Manager GPI, 2nd edition, Winn - I really would like to
review this soon, as I am coming across some stuff that the old one doesn't
handle in an up-to-date manner, and want to see what the new one is all about.
Visual Age: Concepts and Features, ? - This sounds interesting.
If anyone has a book they want to see reviewed, I will be happy to oblige. Just
mail me and tell me which. Publishers can send me books at the address on my
personal page at the end of the magazine, and I will review all OS/2
development-related and advanced user books I receive.
The Codesmith's Library - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 7. REXX Inside and Out ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 7.1. REXX Inside and Out ΓòÉΓòÉΓòÉ
REXX Inside and Out
Written by Carsten Whimster
Introduction
Several years ago I wrote programs in the SAS language to interrogate the MVS
operating system's resources and configuration. Because of the interpretive
nature of SAS, it was possible for one program to write new sections of code
based on elements defined to the system, place them in temporary data sets, and
then include them later in the program. Now instead of needing to keep static
tables of resource information that were manually updated, I was able to
provide a maintenance free application that could adjust itself to changes in
the operating environment. I named the program SAS007 (007 as in James Bond)
because of its sneaky nature. "You mean your program writes itself, executes,
and then goes away so that there is no chance to debug it or see what was going
on?", a co-worker asked one day while examining my program and slowly shaking
her red head. "Slick, huh?", I boasted. She handed my program back, and with
a chuckle she added, "I never really did like dynamically self-violating code
myself."
I've learned quite a bit since that time, but the old temptations return when
dealing with REXX and automation. "REXX is an interpretive language, right?",
I ask myself. "Why not write some of that self-violating stuff that will adapt
to the variations in the system? I could stuff some dynamic code into a file
and then... No WAIT! I could put a bunch of code into a buffer and invoke the
INTERPRET instruction! Yeah. That's the ticket!" Usually it's about now that
reality hits me and I realize that even though the language supports it, it
might not be such a good idea to use it.
Although we will discuss the INTERPRET instruction, this column is dedicated to
the avoidance of "dynamically self-violating" code.
REXX Inside and Out - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 7.2. Interpret ΓòÉΓòÉΓòÉ
Interpret
INTERPRET is one of those statements that if you need it you have to have it,
but you pray that you will never need it. At least that is what I have heard.
In my seven years of REXX programming, although I have played with INTERPRET, I
have never "needed" the instruction badly enough to use it in a production
level program. The statement usually renders the program unmaintainable by
anyone but its author unless the author has slept since the program was
written. (if the author has slept since the program's conception there is a
great chance that he/she will be unable to easily update the code) "Couldn't
you just fully document the use of this instruction in your program so that its
intended purpose is apparent?", you ask. "Well... I have to believe that
anybody who would not find away around using this instruction would not bother
to comment their code." (That last statement was placed in quotes because it
is certain that there are people out there who have had a valid need for this
instruction and have taken great pains to comment the reasons for its use.
Call it a gross generality if you would like.) There is a further reason to
refrain from the use of the INTERPRET instruction. The IBM compilers for REXX
(no, they don't exist for OS/2 at this time and may never) do not support it.
So why am I spending time telling you about an instruction that is at least as
wicked as a GOTO? Can you say "Quick and Dirty programming?" I thought you
could. When developing one shot tools or tools for self use this can solve
some problems.
While an entire program section can be placed in a buffer and used dynamically
with the INTERPRET instruction, our example will only interpret one instruction
at a time.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
/* quick and dirty calculator */
x = 0 /* initialize displayed variables */
y = 0
z = 0
Say "x =" x /* display variable content and availability */
Say "y =" y
Say "z =" z
call charout ,"===> " /* input prompt */
pull stuff /* get equation */
do while (stuff <> "EXIT")
INTERPRET stuff /* evaluate equation */
Say "x =" x
Say "y =" y
Say "z =" z
call charout ,"===> "
pull stuff
end
exit
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Figure 1) A simple example of INTERPRET.
The above program accepts user input such as "x = y + 56 / 8.3", evaluates the
expressions with the INTERPRET instruction, displays the results, and gathers
more input until the word "exit" is entered; or the word "barf" is entered; or
the phrase "I'll bet you can't handle this input" is entered. This program
would be quite a bit longer were it to take the time to evaluate the equation
on its own instead of using INTERPRET. There is one other interesting feature
of this bullet proof code that is a bit off of the topic that should be noted
here.
Many people desire a prompt line before their "pull" instruction. This is
accomplished with the use of charout() with a null parameter for the file name.
It was mentioned earlier that an entire program section could be placed into a
variable and included as part of your program with the INTERPRET instruction.
To accomplish this nasty habit, each statement must be delimited by a
semicolon.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
:
buffer = "Var" || count "=" count"; say Var" || count
INTERPRET buffer
:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
The above lines assign a value to a variable created by the text "Var" and the
value of the variable "count" and display the contents of this new data. This
example was included to show multiple program statements within a single
INTERPRET, but also included to show a common misuse of this instruction. REXX
contains a function that will perform this variable manipulation without the
smoke and mirrors of INTERPRET.
REXX Inside and Out - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 7.3. Value() ΓòÉΓòÉΓòÉ
Value()
The value function has three arguments by definition:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
target = Value( variable_name, new_value, selector );
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
variable_name - since the name of a variable is an argument, variables can be
created dynamically. The previous use of INTERPRET created a variable, "Var"
|| count. Value() could be used to create this variable by passing the same
information in the first argument.
new_value - the variable created or addressed by the first argument is assigned
whatever value is referenced by this argument.
selector - this is a special argument and for basic variable manipulation
should contain a null value. As far as I can determine, the only valid
non-null value for this argument is OS2ENVIRONMENT. When OS2ENVIRONMENT is
used, the current session environment is interrogated to solve the value
request.
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
current_path = Value("PATH", , "OS2ENVIRONMENT")
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
The above call to value() would retrieve the value of the session's current
"PATH" environment variable but would not change its value because the
new_value argument was left blank.
returns - value() returns the value of the variable referenced by the first
argument before the new value is assigned.
The last INTERPRET example could have been replaced with the more efficient and
compiler friendly
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
:
call value "Var" || count, count
Say value("Var" || count)
:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
A further example:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
:
drives = SysDriveMap("C:", "USED") /* get list of available DASD */
do words( drives )
parse var drives singleton drives /* loop through drive letters */
info = SysDriveInfo( singleton ) /* get disk drive information */
call value word(info, 4), word(info, 2) /* create var with disk name */
end
:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Figure 2) A simple example of Value().
The above program segment creates a variable for each disk drive starting with
C: and assigns it the value of the number of freespace bytes left on the drive.
This is a less contrived use of Value(), but it still is too complex.
REXX Inside and Out - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 7.4. Reality ΓòÉΓòÉΓòÉ
Reality
While Value() is certainly a nifty little function, the only use of it that can
be found in programs that leave my machine are to reference the OS/2
environment. REXX's compound variable structures are powerful enough to thwart
any of my contrived "needs" for the value() function.
The previous Value() example could have avoided any confusing use of the
Value() function by being coded as follows:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
:
drives = sysDriveMap("C:", "USED")
do words( drives )
parse var drives singleton drives
info = SysDriveInfo( singleton )
drive_name = word( info, 4 )
drive_free_space.drive_name = word( info, 2 )
end
:
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
Figure 3) Cleanup up the Value() example.
Four out of five programmers agree that this example is clearer than the last
Value() example. "But gee, Uncle Bob, aren't compound variables slow?", you
might ask.
REXX's variable pools are kept in efficient tree structures so that their
manipulation does not slow down the program. If speed is really a concern it
might be noted that this example also eliminates a function call!
REXX Inside and Out - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 7.5. Conclusion ΓòÉΓòÉΓòÉ
Conclusion
REXX is a powerful language that can support all of the bad programming
practices of my youth. "Dynamically self- violating code" is even easier to
create in REXX than it was in the SAS language. So why not go let all of this
power go to my head and just start including INTERPRET statements and Value()
calls any place I think it might be "neat"?
Gather around, Kiddies, and let old Uncle Bob tell you a story. Remember
SAS007? That slick piece of code ran daily for a couple of years after I left
the company for which it was written. One day (ok, probably over a weekend)
the version of MVS was upgraded a to a new version (MVS/XA). This version
changed the location of some of the information that SAS007 was gathering.
Instead of being able to make some simple code changes to update the program to
run with the new operating system version it was labeled as spooky and tossed
aside like a useless piece of garbage. So all of the time that the company had
invested for me to write that program was wasted because it had to be written
again.
As we've seen here, straight forward code can even be more efficient than
"slick" code. Most programmers not only desire their work to be efficient, but
long lived. Let's face it. Our programs are the main tools a programmer has
to make a name for himself. Slick code will make a name for the programmer.
What will that name change to when the code breaks and the company that paid
for its development gets to keep both pieces?
REXX Inside and Out - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 8. The Codesmith's Library ΓòÉΓòÉΓòÉ
ΓòÉΓòÉΓòÉ 8.1. The Codesmith's Library ΓòÉΓòÉΓòÉ
The Codesmith's Library
Written by Carsten Whimster
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
In The Codesmith's Library, I focus on development books and materials. I
write this column from the point of view of an intermediate PM C programmer and
intermediate REXX programmer. Pick up whichever book strikes your fancy, and
join the growing group of people following our PM programming columns. I have
already reviewed a number of beginner books, and will try to concentrate more
on intermediate techniques and special topics from now on.
Please send me your comments and thoughts so that I can make this column what
you want it to be. I read and respond to all mail.
This mini review will be an occasional column which covers development-related
books that are not OS/2-specific. It will not cover books that are specific to
any O/S at all, but will rather cover books of importance to the developer
segment in general. Because these books are not OS/2 specific, I will keep the
review shorter than a full review, and will just focus on describing the book
in general strokes.
Writing Solid Code is the best non-OS/2 book I have read in a long time. It
focuses on the prevention of bugs.
The Codesmith's Library - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 8.2. Writing Solid Code ΓòÉΓòÉΓòÉ
Writing Solid Code
This book maybe one of the most important books to come out in a long time,
especially right now. It focuses on how to avoid writing bugs, how to prevent
bugs, and how to fix bugs properly. Here are the chapters:
1. A Hypothetical Compiler
2. Assert Yourself
3. Fortify Your Subsystems
4. Step Through Your Code
5. Candy-Machine Interfaces
6. Risky Business
7. Treacheries of the Trade
8. The Rest is Attitude
Epilogue: Where Do You Go from Here?
Appendix A: Coding Checklists
Appendix B: Memory Logging Routines
Appendix C: Answers
It is interesting that this book should come from Microsoft. There have been
many public statements by (sometimes anonymous) officials at Microsoft, saying
things like "you only ever have to get 90% of the product working", in
addition to the extraordinary bugginess of the initial release of Word 6.0,
and on and on. It is interesting to note that Maguire no longer seems to work
for Microsoft. I can't offer any explanation for these seeming
contradictions, only suggest that this book was ignored by the programmers of
Word and Windows 95, and followed strictly by the NT programmers <grin>.
The book starts with a short intro, which among other things encourages the
use of Hungarian Notation for variable naming. I was able to find these
notations on the web fairly easily by searching for "Hungarian AND Notation"
on Yahoo and Web Crawler.
Chapter 1 discusses a hypothetical compiler which is able to catch all
problems in your code. Maguire goes on to explain that of all the most
desirable error messages, many are already implemented in modern compilers,
but most people turn off this error detection because they either do not
understand the message, or they code in unsafe ways and find the messages
annoying. He goes on to recommend the use of lint and other tools, on a
religious basis. At the end of this and all the chapters, there is a short
section with questions to encourage the reader to think more about the
underlying issues of the chapter. There is even a little suggested project
for the reader to perform, if he or she is very enthusiastic.
Chapter 2 weighs the pros and cons of the standard C library's assert, and
then goes on to define a better one. This is then demonstrated with several
code examples. Again, the emphasis here is on the prevention and automatic
detection of bugs. Documentation of tricky code is also recommended, again
with some real examples. Most of the examples in this book are taken from the
real process of developing Excel, mostly on the Mac. Maguire started as a
programmer for Excel, and later moved up to be a team lead. The assert
routine developed by Maguire is used in a variety of different situations to
detect a multitude of hard-to-spot bugs lurking in the wings of the
application.
Fortifying your subsystems is the theme of chapter 3. The intent here is that
you should provide debug-only double- checks of important algorithms, ensure
that all code runs in testing, destroying garbage, initializing memory, and so
on. These checks mostly occur at debug-time only, of course, so as to avoid
slowing down the gold code.
Stepping through your code with a debugger is the topic of chapter 4. This
seemingly time-wasting trick will save lots of time debugging code that never
worked quite right in the first place, but it has to be done when the code was
written, and the ideas clear in the mind of the programmer, of course, not two
years later.
In chapter 5, Maguire makes an interesting comparison between function
interfaces and candy-machine interfaces. Writing function interfaces in such
a way as to be unambiguous is more important than apparent at first, and even
the standard C library is rife with examples of poor interfaces. One example
is getchar() which returns, of course, an int! Separating error codes from
return values is but one piece of advice you will find in this chapter.
Risk, and proper use of the language is the major topic of chapter 6. It is
amazing how many programmers will code a straight-forward task in a quirky,
non-portable way, only because it seems more clever or faster, when in fact it
is neither. Discover other language tips in chapter 6.
Resisting the temptation of writing clever, but obscure code is one of the
focuses of chapter 7. Not referencing memory already freed is yet another tip,
which seems all to obvious, but which many programmers do nevertheless. Treat
input parameters as read-only, output-parameters as write- only, and so on.
Not falling into the trap of thinking that tight C means tight machine code is
yet another example. Use the debugger to get a feel for what code the
compiler generates here. Finally, a little-realized aspect of development is
that novice programmers tend to be the ones who maintain code, so experienced
programmers should resist the temptation to write difficult to understand
code, in all but the most extreme situations, since this code will not be
understood, and thus most likely be ripped out by maintenance programmers.
In the last chapter we are told to get the correct attitude to go along with
all our new-found knowledge of bugs. Bugs never just disappear by themselves,
for example, yet many programmers use this as an excuse. Do not add extra
unnecessary features to products just because they are easy to add either,
since this new (easy) code is yet another spot where bugs can hide and bite
you from. This last chapter has many other great suggestions.
The real strength of this book is that the tips themselves often sound silly,
derogatory, and obvious, but in the context of the examples given, I came to
realize again and again that I too had fallen for many of these traps. Read
the whole book, page for page, and follow the advice given.
The Codesmith's Library - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 8.3. Summary ΓòÉΓòÉΓòÉ
Summary
This book is very important, and every serious developer should take a jet, not
run, to the nearest bookstore to pick up a copy. It has an incredible array of
methods for avoiding and fighting bugs, and in these bug- ridden, bloated code
days, this is more important than ever before in history. Do not assume that
you can do the things I mentioned in this review, and be done. They are only
representative of what Maguire discusses. This books is so full of tricks and
explanations that you just do not want to miss, and this book is really cheap
and well worth the money. A+.
The Codesmith's Library - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 8.4. Book Reviewed ΓòÉΓòÉΓòÉ
Book Reviewed
Writing Solid Code, Maguire
- Microsoft Press, ISBN 1-55615-551-4, $US24.95, $32.95CAN, UK21.95.
- Intended audience: C/C++ Programmers
- Mark: A+
A great little cheap book on avoiding, fighting, and automatically
preventing bugs. Every programmer in the world should own a copy of this
great book, and should use it religiously.
NOTES
Please note that books aimed at different audiences should only be compared
with great care, if at all. I intend to concentrate on the strong points of
the books I review, but I will point out any weaknesses in a constructive
manner.
LEGEND
BOOK: The name of the book, and the author(s)
PUBLISHING INFORMATION: Publishing company, ISBN, and approximate price.
AUDIENCE: This is a description of the audience I think the book targets
best. This is not intended as gospel, just a guideline for people not
familiar with the book.
MARK: My opinion of the success of the book's presentation, and how well it
targets its audience. Technical content, accuracy, organization, readability,
and quality of index all weigh heavily here, but the single most important
item is how well the book covers what it says it covers. Many books try to
cover too much, and get a lower mark as a result.
+------+-------------------------------------------------------------------------+
| MARK | DESCRIPTION |
+------+-------------------------------------------------------------------------+
| A+ | Ground-breaking, all-around outstanding book |
| A | Excellent book. This is what I want to see happen a lot |
| A- | Excellent book with minor flaws |
| B+ | Very good book with minor flaws or omissions |
| B | Good book with some flaws and omissions |
| B- | Good book, but in need of improvement |
| C+ | Mediocre book with some potential, but in need of some updating |
| C | Mediocre book with some good sections, but badly in need of fixing |
| C- | Mediocre book, little good material, desperately in need of an overhaul |
| D | Don't buy this book unless you need it, and nothing else exists |
| F | Don't buy this book. Period |
+------+-------------------------------------------------------------------------+
COMMENTS: This is a very brief summary of the review proper.
The Codesmith's Library - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 8.5. Coming Up ΓòÉΓòÉΓòÉ
Coming Up
My next mini review will be Code Complete.
Other books I have:
Code Complete, McConnell - The next book in this series from Microsoft Press
Algorithms in C++, Sedgewick - This classic has a place in every C++
developer's library
Zen of Code Optimization, Abrash - An exiting book about writing fast code the
right way
Other books I would like to review:
Enough Rope to Shoot Yourself in the Foot, Holub
Software Testing, Roper
Error Coding Cookbook, Rorabaugh
Applied Cryptography, Schneier
Software Reuse, Karlsson
If anyone has a book they want to see reviewed, I will be happy to oblige. Just
mail me and tell me which. Publishers can send me books at the address on my
personal page at the end of the magazine, and I will review all OS/2
development- related and advanced user books I receive.
The Codesmith's Library - EDM/2 - Jul 1996 - Volume 4 Issue 6
ΓòÉΓòÉΓòÉ 9. Contributors to this Issue ΓòÉΓòÉΓòÉ
Are You a Potential Author?
We are always looking for authors. If you have a topic about which you would
like to write, send a brief description of the topic electronically to any of
the editors by the 15th of the month before the month in which your article
will appear. This alerts us that you will be sending an article so that we can
plan the issue layout accordingly.
After you have done this, read the latest copy of the Article Submission
Guidelines on our web site or download them to your machine also from our web
site. These guidelines contain everything you need to know about writing an
article for EDM/2.
The editors can be reached at the following email addresses:
Larry Salomon - larry_salomon@iqpac.com (Internet).
Carsten Whimster - carsten_whimster@iqpac.com (Internet).
The following people contributed to this issue in one form or another (in
alphabetical order):
Stefan Ruck
Larry Salomon, Jr.
Brad Scharf
Carsten Whimster
Joe Wyatt
Gordon Zeglinski
Network distributors
Contributors - EDM/2 - Jul 1996 - Volume 4, Issue 6
ΓòÉΓòÉΓòÉ 9.1. Stefan Ruck ΓòÉΓòÉΓòÉ
Stefan Ruck
Stefan Ruck is working as a PC programer under DOS in a small software company.
He got in touch with computers about 15 years ago at school and started
programing BASIC on a Commodore VIC20. He also did a little bit of assembler
on this machine. Later on he learned COBOL and structured programing on IBM
mainframes. Since about 6 years ago, he's been doing C programing on DOS PCs.
After a short look at Windows 1 1/2 a year ago he started OS/2 programing in
C++ in his spare time to learn a little bit more about GUIs and C++ and to see
something new and different.
He can be reached via CompuServe at 100664,1353 or via the Internet at
100664.1353@compuserve.com.
Contributors - EDM/2 - Jul 1996 - Volume 4, Issue 6
ΓòÉΓòÉΓòÉ 9.2. Larry Salomon, Jr. ΓòÉΓòÉΓòÉ
Larry Salomon Jr.
Larry Salomon Jr. has been developing OS/2 applications since version 1.1 in
1989. He has written numerous applications, including the Scramble applet that
was included in OS/2 versions 2.0-2.11, and the I-Brow, Magnify, and Screen
Capture trio that has been distributed on numerous CD-ROMs.
Larry is also the coauthor of the successful book, The Art of OS/2 2.1 C
Programming (Wiley-QED). Finally, he is the CEO/President of IQPac Inc. which
is responsible for the publication of EDM/2, and he is a frequent contributor
to the publication.
Larry can be reached electronically via the Internet at
larry_salomon@iqpac.com.
Contributors - EDM/2 - Jul 1996 - Volume 4, Issue 6
ΓòÉΓòÉΓòÉ 9.3. Brad Scharf ΓòÉΓòÉΓòÉ
Brad Scharf
Brad discovered computers while enrolled in a Chemistry B.Sc. program and soon
switched to Computer Science. He has been using OS/2 since the release of
version 2.0, has used OS/2 exclusively since version 2.1, and is now in the
process of teaching himself PM programming.
Brad can be reached via the Internet at brad_scharf@iqpac.com.
Contributors - EDM/2 - Jul 1996 - Volume 4, Issue 6
ΓòÉΓòÉΓòÉ 9.4. Carsten Whimster ΓòÉΓòÉΓòÉ
Carsten Whimster
Carsten is an undergraduate Computer Science student at the University of
Waterloo. He is currently in fourth year, and enjoying it immensely. He uses
Visual Age C++, Watcom C/C++ 10.0a and Watcom VX-REXX 2.0c. Carsten is the
author of some commandline utilities, and POV-Panel/2. He is also a TEAM-OS/2
member.
You may reach Carsten...
...via email (Internet):
carsten_whimster@iqpac.com
...via the World Wide Web:
http://www.undergrad.math.uwaterloo.ca/~bcrwhims/
Please note the changed address and phone number
...via snail mail:
Carsten Whimster
43 Wilhelm Street, apt. 2
Kitchener, Ontario
Canada
N2H 5R9
...via voice:
(519)749-2391
Contributors - EDM/2 - Jul 1996 - Volume 4, Issue 6
ΓòÉΓòÉΓòÉ 9.5. Joe Wyatt ΓòÉΓòÉΓòÉ
Joe Wyatt
Joe has been working in OS/2 since 1.3 and has programmed in Rexx on four
different platforms. Rexx projects have included elegant, complex systems in
both VM and OS/2, operating system automation in MVS, and your basic "quick and
dirty" tools in DOS. He has recently mustered up the courage to jump into the
world of consulting and self-employment. (God help him.) He makes his home in
San Antonio, Texas with a wife and four children (along with 2 dogs, 1 cat, 1
turtle, varying numbers of fish, and a rabbit).
He can be reached via internet address joe_wyatt@iqpac.com for comments and
criticisms.
Contributors - EDM/2 - Jul 1996 - Volume 4, Issue 6
ΓòÉΓòÉΓòÉ 9.6. Gordon Zeglinski ΓòÉΓòÉΓòÉ
Gordon Zeglinski
Gordon Zeglinski is a freelance programmer/consultant who received his Master's
degree in Mechanical Engineering with a thesis on C++ sparse matrix objects.
He has been programming in C++ for 6 years and also has a strong background in
FORTRAN. He started developing OS/2 applications with version 2.0 .
His current projects include a client/server communications program that
utilitizes OS/2's features which has entered beta testing. Additionally, he is
involved in the development of a "real-time" automated vehicle based on OS/2
and using C++ in which he does device driver development and designs the
applications that comprise the control logic and user interface.
He can be reached via the Internet at gordon_zeglinski@iqpac.com.
Contributors - EDM/2 - Jul 1996 - Volume 4, Issue 6
ΓòÉΓòÉΓòÉ 9.7. Network distributors ΓòÉΓòÉΓòÉ
Network Distributors
These people are part of our distribution system to provide EDM/2 on networks
other than the Internet. Their help to provide access to this magazine for
others is voluntary and we appreciate them a lot!
Paul Hethmon (phethmon@utk.edu) - Compuserve
Gess Shankar (gess@knex.mind.org) - Internet
Jason B. Tiller (PeerGynt@aol.com) - America On-line
Jesper Nielsen (jesniels@internet.dk) - Denmark BBS's
Gess is temporarily out of commission while he changes Internet domains.
If you would like to become a "network distributor", be sure to contact the
editors so that we can give you the credit you deserve!
Contributors - EDM/2 - Jul 1996 - Volume 4, Issue 6